﻿using BTechBids.Data;
using BTechBids.DataModels;
using BTechBids.Web.IDataAdapters.Interfaces;
using BTechBids.Web.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace BTechBids.Web.IDataAdapters.Adapters
{
    public class ItemAdapter : IItemAdapter
    {
        public ItemVM AddItem(ItemVM vm)
        {
            Item item;
            using (ApplicationDbContext db = new ApplicationDbContext())
            {
                item = new Item(db.Categories.FirstOrDefault(x => x.Name == vm.Category).Id, vm.Name, vm.Description);
                //item.msRemaining = 900000;
                var rand = new Random();
                item.msRemaining = rand.Next(60000, 900000);
                item = db.Items.Add(item);
                db.SaveChanges();

                List<ImageUrl> images = vm.imageUrl.Select(x => new ImageUrl(item.Id, x)).ToList();
                db.Images.AddRange(images);
                db.SaveChanges();

                vm.Id = item.Id;
                vm.msRemaining = item.msRemaining;
                vm.Cost = item.Cost;
            }
            return vm;
        }

        public List<Models.ItemVM> GetAllItems()
        {
            List<Models.ItemVM> items;
            using (ApplicationDbContext db = new ApplicationDbContext())
            {
                items = db.Items.OrderBy(x => x.Name).Where(x => x.IsActive == true).Select(y => new ItemVM()
                {
                    Id = y.Id,
                    Name = y.Name,
                    Description = y.Description,
                    Category = db.Categories.Where(x => x.Id == y.CategoryId).Select(z => z.Name).FirstOrDefault(),
                    Cost = y.Cost,
                    imageUrl = db.Images.Where(x => x.ItemId == y.Id).Select(z => z.Url).ToList(),
                    msRemaining = y.msRemaining,
                    IsActive = y.IsActive,
                    UserName = db.Bids.Where(x => x.ItemId == y.Id).OrderByDescending(z => z.Timestamp).Any() ? db.Bids.Where(x => x.ItemId == y.Id).OrderByDescending(z => z.Timestamp).Select(n=>n.ApplicationUser.UserName).FirstOrDefault() : default(string)
                }).ToList();

            }
            return items;
        }

        public Models.ItemVM GetItem(int id)
        {
            ItemVM item;
            using (ApplicationDbContext db = new ApplicationDbContext())
            {
                item = db.Items.Where(x => x.Id == id).Select(y => new ItemVM()
                {
                    Id = y.Id,
                    Name = y.Name,
                    Description = y.Description,
                    Category = db.Categories.Where(x => x.Id == y.CategoryId).Select(z => z.Name).FirstOrDefault(),
                    Cost = y.Cost,
                    imageUrl = db.Images.Where(x => x.ItemId == y.Id).Select(z => z.Url).ToList(),
                    IsActive = y.IsActive,
                    msRemaining = y.msRemaining,
                    UserName = db.Bids.Where(x => x.ItemId == y.Id).OrderByDescending(z => z.Timestamp).Any() ? db.Bids.Where(x => x.ItemId == y.Id).OrderByDescending(z => z.Timestamp).Select(n => n.ApplicationUser.UserName).FirstOrDefault() : default(string)
                }).FirstOrDefault();
            }
            return item;
        }

        public void UpdateItemOnBid(Models.ItemQuickUpdateVM biditem)
        {
            using (ApplicationDbContext db = new ApplicationDbContext())
            {
                Item item = db.Items.FirstOrDefault(x => x.Id == biditem.Id);
                item.Cost = biditem.Cost;
                item.msRemaining = biditem.msRemaining;

                ApplicationUser user = db.Users.FirstOrDefault(x => x.UserName == biditem.UserName);
                Bid bid = new Bid(item.Id, user.Id, biditem.Cost);
                user.BidCount--;
                db.Bids.Add(bid);
                db.SaveChanges();
            }
        }

        public void FinalizeAuctionForItem(ItemVM itemVM)
        {
            using (ApplicationDbContext db = new ApplicationDbContext())
            {
                Item item = db.Items.FirstOrDefault(x => x.Id == itemVM.Id);
                item.Cost = itemVM.Cost;
                item.msRemaining = 0;
                item.IsActive = false;
                db.SaveChanges();

                Bid bid = db.Bids.Where(x => x.ItemId == item.Id).OrderByDescending(x => x.Timestamp).FirstOrDefault();
                if (bid == null)
                {
                    return;
                }
                Win win = new Win(item.Id, bid.ApplicationUserId, bid.Id, bid.BidPrice);

                db.Wins.Add(win);
                db.SaveChanges();

            }
        }

        public ItemVM UpdateItem(ItemVM itemvm)
        {
            using (ApplicationDbContext db = new ApplicationDbContext())
            {
                Item olditem = db.Items.Find(itemvm.Id);
                olditem.Name = itemvm.Name;
                olditem.CategoryId = db.Categories.FirstOrDefault(x => x.Name == itemvm.Category).Id;
                olditem.Description = itemvm.Description;
                db.Images.RemoveRange(db.Images.Where(x => x.ItemId == itemvm.Id).ToList());
                List<ImageUrl> images = itemvm.imageUrl.Select(x => new ImageUrl(itemvm.Id, x)).ToList();
                db.Images.AddRange(images);
                db.SaveChanges();
            }
            return itemvm;
        }

        public void DeleteItem(int id)
        {
            using (ApplicationDbContext db = new ApplicationDbContext())
            {
                Item item = db.Items.Include("Images").FirstOrDefault(x => x.Id == id);
                db.Items.Remove(item);
                db.SaveChanges();
            }
        }


        public List<ItemUserVM> GetUserWins(string username)
        {
            List<ItemUserVM> userItems = new List<ItemUserVM>();
            using (ApplicationDbContext db = new ApplicationDbContext())
            {
                ApplicationUser user = db.Users.FirstOrDefault(x => x.UserName == username);

                userItems = db.Wins.Include("Items").Include("Images").Include("Categories").Where(x => x.ApplicationUserId == user.Id).Select(y => new ItemUserVM()
                {
                    Id = y.ItemId,
                    Name = y.Item.Name,
                    Category = y.Item.Category.Name,
                    Description = y.Item.Description,
                    Cost = y.Item.Cost,
                    Images = y.Item.Images.Select(i => i.Url).ToList(),
                    WinId = y.Id,
                    UserName = user.UserName,
                    WasPurchased = y.WasPurchased
                }).ToList();
            }

            return userItems;
        }

        public int GetUserBids(string username)
        {
            int bids;
            using (ApplicationDbContext db = new ApplicationDbContext())
            {
                ApplicationUser user = db.Users.FirstOrDefault(x => x.UserName == username);
                bids = user.BidCount;
            }
            return bids;
        }
        public UserVM UpdateUserAccount(string username, int addBids = 0, double addOrSubtractMoney = 0.0)
        {
            UserVM uservm;
            using (ApplicationDbContext db = new ApplicationDbContext())
            {
                ApplicationUser user = db.Users.FirstOrDefault(x => x.UserName == username);
                uservm = new UserVM()
                {
                    Id = user.Id,
                    FirstName = user.FirstName,
                    UserName = user.UserName,
                    LastName = user.LastName,
                    Email = user.Email,
                    BidCount = user.BidCount += addBids,
                    Wallet = user.Wallet += addOrSubtractMoney,
                    InvoiceDue = db.Wins.Include("Items").Where(x => x.ApplicationUserId == user.Id && x.WasPurchased == false).Any() ? db.Wins.Include("Items").Where(x => x.ApplicationUserId == user.Id && x.WasPurchased == false).Sum(x => x.Item.Cost) : default(double)
                };
                db.SaveChanges();
            }
            return uservm;
        }



        public void SettleUserAccount(string username)
        {
            UserVM uservm;
            using (ApplicationDbContext db = new ApplicationDbContext())
            {
                ApplicationUser user = db.Users.FirstOrDefault(x => x.UserName == username);
                uservm = new UserVM()
                {
                    Id = user.Id,
                    FirstName = user.FirstName,
                    UserName = user.UserName,
                    LastName = user.LastName,
                    Email = user.Email,
                    BidCount = user.BidCount,
                    Wallet = user.Wallet,
                    InvoiceDue = db.Wins.Where(x => x.ApplicationUserId == user.Id && x.WasPurchased == false).Any() ? db.Wins.Where(x => x.ApplicationUserId == user.Id && x.WasPurchased == false).Sum(x => x.Item.Cost) : default(double)
                    
                };

                List<Win> wins = db.Wins.Where(x => x.ApplicationUserId == user.Id && x.WasPurchased == false).OrderBy(x => x.Item.Cost).ToList();
                foreach (var win in wins)
                {
                    if (user.Wallet < win.Item.Cost)
                    {
                        break;
                    }

                    user.Wallet -= win.Item.Cost;
                    win.WasPurchased = true;
                }

                db.SaveChanges();
            }
        }


        public List<ItemVM> GetAllItemsForAdmin()
        {
            List<Models.ItemVM> items;
            using (ApplicationDbContext db = new ApplicationDbContext())
            {
                items = db.Items.OrderBy(x => x.Name).Select(y => new ItemVM()
                {
                    Id = y.Id,
                    Name = y.Name,
                    Description = y.Description,
                    Category = db.Categories.Where(x => x.Id == y.CategoryId).Select(z => z.Name).FirstOrDefault(),
                    Cost = y.Cost,
                    imageUrl = db.Images.Where(x => x.ItemId == y.Id).Select(z => z.Url).ToList(),
                    msRemaining = y.msRemaining,
                    IsActive = y.IsActive,
                    UserName = db.Bids.Where(x => x.ItemId == y.Id).OrderByDescending(z => z.Timestamp).Any() ? db.Bids.Where(x => x.ItemId == y.Id).OrderByDescending(z => z.Timestamp).Select(n => n.ApplicationUser.UserName).FirstOrDefault() : default(string)
                }).ToList();

            }
            return items;
        }


        public List<UserVM> GetAllUsers()
        {
            List<Models.UserVM> users;
            using (ApplicationDbContext db = new ApplicationDbContext())
            {
                users = db.Users.OrderBy(x => x.LastName).Select(y => new UserVM()
                    {
                        Id = y.Id,
                        LastName = y.LastName,
                        FirstName = y.FirstName,
                        UserName = y.UserName,
                        Email = y.Email,
                        BidCount = y.BidCount,
                        Wallet = y.Wallet,
                        InvoiceDue = db.Wins.Where(x => x.WasPurchased == false).Any() ? db.Wins.Where(x => x.WasPurchased == false).Sum(z => z.BidPrice): 0
                    }).ToList();

            }
            return users;
        }

        public List<string> GetBidHistory(int id)
        {
            List<string> users;
            using (ApplicationDbContext db = new ApplicationDbContext()){
                users = db.Bids.Include("AspNetUsers")
                    .OrderBy(x=>x.Timestamp).Where(x=>x.ItemId == id)
                    .Select(y=>y.ApplicationUser.UserName).ToList();
            }
            return users;
        }
    }
}